package com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.list

import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import com.gitee.wsl.compose.ui.richtext.edit.annotation.ExperimentalRichTextApi
import com.gitee.wsl.compose.ui.richtext.edit.model.DefaultListIndent
import com.gitee.wsl.compose.ui.richtext.edit.model.DefaultUnorderedListStyleType
import com.gitee.wsl.compose.ui.richtext.edit.model.span.RichSpan
import com.gitee.wsl.compose.ui.richtext.edit.model.RichTextConfig
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.RichParagraph
import com.gitee.wsl.compose.ui.richtext.edit.model.paragraph.type.ParagraphType

class UnorderedList private constructor(
    initialIndent: Int = DefaultListIndent,
    startTextWidth: TextUnit = 0.sp,
    initialLevel: Int = 1,
    initialStyleType: UnorderedListStyleType = DefaultUnorderedListStyleType,
): AbstractList(initialIndent,  startTextWidth, initialLevel) {

    constructor(
        initialLevel: Int = 1,
    ): this(
        initialIndent = DefaultListIndent,
        initialLevel = initialLevel,
    )

    constructor(
        config: RichTextConfig,
        initialLevel: Int = 1,
    ): this(
        initialIndent = config.unorderedListIndent,
        initialLevel = initialLevel,
        initialStyleType = config.unorderedListStyleType,
    )

    override var level:Int = initialLevel
        set(value) {
            field = value
            style = getNewParagraphStyle()
            startRichSpan = getNewStartRichSpan()
        }

    private var styleType: UnorderedListStyleType = initialStyleType
        set(value) {
            field = value
            startRichSpan = getNewStartRichSpan()
        }


    fun updateStyleType(styleType: UnorderedListStyleType) {
        this.styleType = styleType
        startRichSpan = getNewStartRichSpan()
    }

    override fun getStyle(config: RichTextConfig): ParagraphStyle {
        if (config.unorderedListIndent != indent) {
            indent = config.unorderedListIndent
        }

        if (config.unorderedListStyleType != styleType) {
            styleType = config.unorderedListStyleType
        }

        return style
    }

    override fun getNewParagraphStyle() =
        ParagraphStyle(
            textIndent = TextIndent(
                firstLine = (indent * level).sp,
                restLine = ((indent * level) + startTextWidth.value).sp
            )
        )

    @OptIn(ExperimentalRichTextApi::class)
    override fun getNewStartRichSpan(textRange: TextRange ): RichSpan {
        val prefixIndex = (level - 1).coerceIn(styleType.prefixes.indices)

        val prefix = styleType.prefixes.getOrNull(prefixIndex) ?: "•"

        val text = "$prefix "

        return RichSpan(
            paragraph = RichParagraph(type = this),
            text = text,
            textRange = TextRange(
                textRange.min,
                textRange.min + text.length
            )
        )
    }

    override fun getNextParagraphType(): ParagraphType =
        UnorderedList(
            initialIndent = indent,
            startTextWidth = startTextWidth,
            initialLevel = level,
            initialStyleType = styleType,
        )

    override fun copy(): ParagraphType =
        UnorderedList(
            initialIndent = indent,
            startTextWidth = startTextWidth,
            initialLevel = level,
            initialStyleType = styleType,
        )

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is UnorderedList) return false

        if (indent != other.indent) return false
        if (startTextWidth != other.startTextWidth) return false
        if (level != other.level) return false
        if (styleType != other.styleType) return false

        return true
    }

    override fun hashCode(): Int {
        var result = indent
        result = 31 * result + startTextWidth.hashCode()
        result = 31 * result + level
        result = 31 * result + styleType.hashCode()
        return result
    }
}

fun ParagraphStyle.unorderedList(
    config: RichTextConfig,
    level: Int = 1,
): ParagraphType =
    UnorderedList(
        config = config,
        initialLevel = level,
    )

fun ParagraphStyle.unorderedList(
    level: Int = 1,
): ParagraphType =
    UnorderedList(
        initialLevel = level,
    )